﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Markup;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.Diagnostics;
using System.Reflection;
using System.Text.RegularExpressions;
using System.Net.NetworkInformation;
using System.Runtime.InteropServices;

namespace EcbSearch
{
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            Thread receThread = new Thread(new ThreadStart(RecvThread));
            receThread.IsBackground = true;
            receThread.Start();
        }

        List<EcbInfo> EcbLists
        {
            get {
                return (List<EcbInfo>)InfoGrid.ItemsSource;
            }
        }

        int selected_index = -1;

        void query_udp_mssg(string mssg)
        {
            string send_mssg;
            if (mssg == "GetEcbInfo")
            {
                send_mssg = mssg + "\n";
            }
            else if (mssg == "SetIpSeg")
            {
                if (IsIp4Str(IpSegTextBox.Text))
                {
                    var result = MessageBox.Show($"确认更改IP段为:\n"
                                + IpSegTextBox.Text + " ?", $"操作提示", 
                                MessageBoxButton.OKCancel, MessageBoxImage.Question);
                    if (result == MessageBoxResult.OK)
                    {
                        send_mssg = mssg + "\n" + IpSegTextBox.Text + "\n";
                    }
                    else
                    {
                        send_mssg = null;
                    }
                }
                else
                {
                    MessageBox.Show($"输入错误！！！");
                    send_mssg = null;
                }
            }
            else if (mssg == "SetIpAddr")
            {
                if (selected_index >= 0)
                {
                    var info = EcbLists[selected_index];
                    if (IsIp4Str(IpTextBox.Text))
                    {
                        var result = MessageBox.Show(
                                    $"确认更改IP {info.IpAddr}为:\n"
                                    + IpTextBox.Text + " ?", $"操作提示",
                                    MessageBoxButton.OKCancel, MessageBoxImage.Question);
                        if (result == MessageBoxResult.OK)
                        {
                            send_mssg = mssg + "\n" + info.IpAddr + "\n" +
                                        info.MacAddr + "\n" + IpTextBox.Text + "\n";
                        }
                        else
                        {
                            send_mssg = null;
                        }
                    }
                    else
                    {
                        MessageBox.Show($"输入错误！！！");
                        send_mssg = null;
                    }
                }
                else
                {
                    MessageBox.Show($"请先选择一个网口！！！");
                    send_mssg = null;
                }
            }
            else
            {
                send_mssg = null;
            }
            if (send_mssg != null)
            {
                InfoGrid.ItemsSource = new List<EcbInfo>();
                SelectIndexLable.Content = "无";
                selected_index = -1;
                var local_addr = GetLocalIp2();
                var UDPsenders = CreateUdp(local_addr);
                IPEndPoint endpoint = new IPEndPoint(IPAddress.Broadcast, 31353);
                byte[] buf = Encoding.Default.GetBytes(send_mssg);
                foreach (var udpsender in UDPsenders)
                {
                    udpsender.Send(buf, buf.Length, endpoint);
                }
            }
        }

        void Search_Click(object sender, RoutedEventArgs e)
        {
            query_udp_mssg("GetEcbInfo");
        }

        void IpSegSet_Click(object sender, RoutedEventArgs e)
        {
            query_udp_mssg("SetIpSeg");
        }

        void Conflic_Click(object sender, RoutedEventArgs e)
        {
            string result = null;
            for (int i = 0; EcbLists != null && i < EcbLists.Count; i++)
            {
                for (int j = i + 1; j < EcbLists.Count; j ++)
                {
                    if (EcbLists[i].IpAddr == EcbLists[j].IpAddr)
                    {
                        result += String.Format("IP [{0}] 和 [{1}]: {2}\n",
                                       i, j, EcbLists[i].IpAddr);
                    }
                }
            }
            for (int i = 0; EcbLists != null && i < EcbLists.Count; i++)
            {
                for (int j = i + 1; j < EcbLists.Count; j++)
                {
                    if (EcbLists[i].MacAddr == EcbLists[j].MacAddr)
                    {
                        result += String.Format("MAC [{0}] 和 [{1}]: {2}\n",
                                       i, j, EcbLists[i].MacAddr);
                    }
                }
            }
            if (result != null)
            {
                MessageBox.Show($"以下有冲突！！！\n" + result);
            }
            else
            {
                MessageBox.Show($"没有冲突！！！");
            }
        }

        void SetIp_Click(object sender, RoutedEventArgs e)
        {
            query_udp_mssg("SetIpAddr");
        }

        void SelectedCellsChanged_Click(object s, SelectedCellsChangedEventArgs e)
        {
            var info = InfoGrid.CurrentItem as EcbInfo;
            if (info != null) 
            {
                SelectIndexLable.Content = "[" + info.Index.ToString() + "] "
                                            + info.IpAddr;
                selected_index = info.Index;
            }
        }
        void RecvThread()
        {

            UdpClient UDPrece = null;
            try
            {
                UDPrece = new UdpClient(new IPEndPoint(IPAddress.Any, 31096));
            }
            catch
            {
                this.Dispatcher.Invoke(new Action(delegate
                {
                    MessageBox.Show($"端口占用，请重试！！！");
                }));
                Environment.Exit(0);
            }
            IPEndPoint endpoint = new IPEndPoint(IPAddress.Any, 0);
            while (true)
            {
                byte[] buf = UDPrece.Receive(ref endpoint);
                string msg = Encoding.Default.GetString(buf);
                string[] words = msg.Split('\n');
                this.Dispatcher.Invoke(new Action(delegate
                {
                    if (words.Length >= 4)
                    {
                        EcbInfo item = new EcbInfo();
                        item.IpAddr = words[0];
                        item.MacAddr = words[1];
                        item.Version = words[2];
                        item.BoardType = words[3];
                        if (EcbLists != null &&
                            !EcbLists.Exists(t => (t.MacAddr == item.MacAddr)))
                        {
                            item.Index = EcbLists.Count;
                            EcbLists.Add(item);
                            InfoGrid.Items.Refresh();
                        }
                    }
                }));
                //Thread.Sleep(100);
            }
        }

        static void TestLocalIp(NetworkInterfaceType _type)
        {
            string output = "";
            foreach (var item in NetworkInterface.GetAllNetworkInterfaces())
            {
                if (item.NetworkInterfaceType == _type &&
                    item.OperationalStatus == OperationalStatus.Up)
                {
                    foreach (var ip in item.GetIPProperties().UnicastAddresses)
                    {
                        if (ip.Address.AddressFamily == AddressFamily.InterNetwork)
                        {
                            output = ip.Address.ToString();
                            Console.WriteLine("IP Address = " + output);
                        }
                    }
                }
            }
        }

        static List<IPAddress> GetLocalIp2()
        {
            List<IPAddress> ip_list = new List<IPAddress>();
            foreach (var item in NetworkInterface.GetAllNetworkInterfaces())
            {
                if (item.NetworkInterfaceType == NetworkInterfaceType.Ethernet &&
                    item.OperationalStatus == OperationalStatus.Up)
                {
                    foreach (var ip in item.GetIPProperties().UnicastAddresses)
                    {
                        if (ip.Address.AddressFamily == AddressFamily.InterNetwork)
                        {
                            ip_list.Add(ip.Address);
                            Console.WriteLine("IP :" + ip.Address.ToString());
                            break;
                        }
                    }
                }
            }
            return ip_list;
        }

        static IPAddress[] GetLocalIp()
        {
            IPHostEntry ipEntry = Dns.GetHostEntry(Dns.GetHostName());
            IPAddress[] addr = ipEntry.AddressList;
            var result = Array.FindAll(addr,
                           ip => ip.AddressFamily == AddressFamily.InterNetwork);
            return result.ToArray();
        }

        static List<UdpClient> CreateUdp(IPAddress[] Ip4)
        {
            List<UdpClient> UDPsenders = new List<UdpClient>();
            for (int i = 0; i < Ip4.Length; i++)
            {
                // IPAddress.Parse("192.168.0.222")
                // IPAddress.Any
                UDPsenders.Add(new UdpClient(new IPEndPoint(Ip4[i], 0)));
            }
            return UDPsenders;
        }

        static List<UdpClient> CreateUdp(List<IPAddress> Ip4)
        {
            List<UdpClient> UDPsenders = new List<UdpClient>();
            for (int i = 0; i < Ip4.Count; i++)
            {
                // IPAddress.Parse("192.168.0.222")
                // IPAddress.Any
                UDPsenders.Add(new UdpClient(new IPEndPoint(Ip4[i], 0)));
            }
            return UDPsenders;
        }

        static bool IsIp4Str(string str)
        {
            string pattern = @"^\s*(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})\s*$";
            var matches = Regex.Matches(str, pattern);
            if (matches.Count == 1)
            {
                var groups = matches[0].Groups;
                if (groups.Count == (4 + 1))
                {
                    for (int i = 0; i < 4; i++)
                    {
                        try
                        {
                            byte num = byte.Parse(groups[i + 1].Value);
                        }
                        catch
                        {
                            return false;
                        }
                    }
                    return true;
                }
            }
            return false;
        }
    }

    public class EcbInfo
    {
        public int Index{ get; set;}

        // ip addr show dev eth0 | grep -w "inet" |
        // sed 's/^[ \t]*//g' | awk -F '[ /]+' '{print $2}'
        public string IpAddr{ get; set;}

        // ip addr show dev eth0 | grep -w "link/ether" |
        // sed 's/^[ \t]*//g' | awk '{print $2}'
        public string MacAddr{ get; set;}

        // uname -v | awk -v OFS= '{print "r" $8,$4,$5 }'
        public string Version{ get; set;}   

        // cat /sys/firmware/devicetree/base/board_name
        public string BoardType{ get; set;}
    }
}
